package com.example.livereplay.common.service.imp;

import cn.hutool.core.util.ObjectUtil;
import com.example.livereplay.common.model.enity.SysAttachment;
import com.example.livereplay.common.service.FileUploadService;
import com.example.livereplay.exception.BusinessException;
import com.example.livereplay.common.mapper.SysAttachmentMapper;
import com.example.livereplay.common.service.SysAttachmentService;
import com.example.livereplay.utils.file.FileUtil;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.TesseractException;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class FileUploadServiceImpl implements FileUploadService {

    @Value("${web.upload}")
    public String upload;
    // 本地敏感词汇库，可根据实际情况不断扩充
    private static final Set<String> SENSITIVE_WORDS_SET = new HashSet<>();
    static {
        SENSITIVE_WORDS_SET.add("敏感词1");
        SENSITIVE_WORDS_SET.add("敏感词2");
        // 依次添加其他敏感词汇
    }

//    // 图片清晰度阈值，可根据实际需求调整
//    private static final double IMAGE_SHARPNESS_THRESHOLD = 100.0;
//    // 视频清晰度阈值，可根据实际需求调整
//    private static final double VIDEO_SHARPNESS_THRESHOLD = 50.0;

    private boolean reviewAttachment(MultipartFile file) {
        try {
            File tempFile = File.createTempFile("temp", getFileExtension(file.getOriginalFilename()));
            file.transferTo(tempFile);

            String fileExtension = getFileExtension(file.getOriginalFilename());
            if ("docx".equals(fileExtension) || "doc".equals(fileExtension)) {
                if (containsSensitiveWordsInWordFile(tempFile)) {
                    return false;
                }
            } else {
                if (containsSensitiveWords(tempFile)) {
                    return false;
                }
//                if ("jpg".equals(fileExtension) || "jpeg".equals(fileExtension) || "png".equals(fileExtension)) {
//                    if (!isImageSharpEnough(tempFile)) {
//                        return false;
//                    }
//                } else if ("mp4".equals(fileExtension) || "avi".equals(fileExtension)) {
//                    if (!isVideoSharpEnough(tempFile)) {
//                        return false;
//                    }
//                }
            }

            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean containsSensitiveWordsInWordFile(File file) {
        try (FileInputStream fis = new FileInputStream(file);
             XWPFDocument doc = new XWPFDocument(fis);
             XWPFWordExtractor extractor = new XWPFWordExtractor(doc)) {
            String text = extractor.getText();
            return containsSensitiveWords(text);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }



    private boolean containsSensitiveWords(File file) {
        Tesseract tesseract = new Tesseract();
        try {
            String imageText = tesseract.doOCR(file);
            if (StringUtils.isNotBlank(imageText)) {
                for (String sensitiveWord : SENSITIVE_WORDS_SET) {
                    if (imageText.contains(sensitiveWord)) {
                        return true;
                    }
                }
            }
            return false;
        } catch (TesseractException e) {
            e.printStackTrace();
            return false;
        }
    }

    private boolean containsSensitiveWords(String text) {
        if (StringUtils.isNotBlank(text)) {
            for (String sensitiveWord : SENSITIVE_WORDS_SET) {
                if (text.contains(sensitiveWord)) {
                    return true;
                }
            }
        }
        return false;
    }

    private String getFileExtension(String fileName) {
        int dotIndex = fileName.lastIndexOf('.');
        if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
            return fileName.substring(dotIndex);
        }
        return "";
    }

//    private boolean isImageSharpEnough(File imageFile) {
//        Mat image = opencv_imgcodecs.imread(imageFile.getAbsolutePath());
//        double sharpness = calculateImageSharpness(image);
//        return sharpness >= IMAGE_SHARPNESS_THRESHOLD;
//    }
//
//    private double calculateImageSharpness(Mat image) {
//        opencv_core.Laplacian(image, image, opencv_core.CV_64F);
//        opencv_core.Scalar mean, stddev;
//        opencv_core.meanStdDev(image, mean, stddev);
//        return stddev.get(0, 0)[0];
//    }
//
//    private boolean isVideoSharpEnough(File videoFile) {
//        VideoCapture videoCapture = new VideoCapture(videoFile.getAbsolutePath());
//        if (!videoCapture.isOpened()) {
//            return false;
//        }
//
//        Mat frame = new Mat();
//        boolean hasFrame = videoCapture.read(frame);
//        if (!hasFrame) {
//            videoCapture.release();
//            return false;
//        }
//
//        double sharpness = calculateImageSharpness(frame);
//        videoCapture.release();
//        return sharpness >= VIDEO_SHARPNESS_THRESHOLD;
//    }
    @Resource
    private SysAttachmentService attachmentService;

    @Resource
    private SysAttachmentMapper sysAttachmentMapper;
    @Override
    public SysAttachment uploadSingleFile(String fileUrl, String fileName, MultipartFile file) {
        if (!reviewAttachment(file)) {
            return null;
        }
        SysAttachment erpAttachment = commonFileUpload(fileUrl, fileName, file);
        long currentTimeStamp = Instant.now().toEpochMilli();
        erpAttachment.setTime(currentTimeStamp);
        attachmentService.save(erpAttachment);
        return erpAttachment;
    }

    @Override
    public SysAttachment uploadSingleFile(String fileUrl, String fileName, MultipartFile file, List<Integer> validateFileTypeList) {
        SysAttachment erpAttachment = commonFileUpload(fileUrl, fileName, file, validateFileTypeList);
        attachmentService.save(erpAttachment);
        return erpAttachment;
    }

    @Override
    public SysAttachment uploadSingleFile(String fileUrl, String fileName, MultipartFile file, Map<Integer, Long> fileTypeSizeMap) {
        SysAttachment erpAttachment = commonFileUpload(fileUrl, fileName, file, fileTypeSizeMap);
        attachmentService.save(erpAttachment);
        return erpAttachment;
    }

    @Override
    public List<SysAttachment> uploadBatchFile(String fileUrl, List<MultipartFile> files,String type) {
        List<SysAttachment> attachments = new ArrayList<>();
        for (MultipartFile file: files) {
            SysAttachment erpAttachment = commonFileUpload(fileUrl,null, file);
            erpAttachment.setType(type);
            attachments.add(erpAttachment);
        }
        attachmentService.saveBatch(attachments);
        return attachments;
    }

    @Override
    public List<SysAttachment> uploadBatchFile(String fileUrl, List<MultipartFile> files, List<Integer> validateFileTypeList) {
        List<SysAttachment> attachments = new ArrayList<>();
        for (MultipartFile file : files) {
            SysAttachment erpAttachment = commonFileUpload(fileUrl, null, file, validateFileTypeList);
            attachments.add(erpAttachment);
        }
        attachmentService.saveBatch(attachments);
        return attachments;
    }

    @Override
    public List<SysAttachment> uploadBatchFile(String fileUrl, List<MultipartFile> files, Map<Integer, Long> fileTypeSizeMap) {
        List<SysAttachment> attachments = new ArrayList<>();
        for (MultipartFile file : files) {
            SysAttachment erpAttachment = commonFileUpload(fileUrl, null, file, fileTypeSizeMap);
            attachments.add(erpAttachment);
        }
        attachmentService.saveBatch(attachments);
        return attachments;
    }


    private SysAttachment commonFileUpload(String fileUrl, String fileName, MultipartFile file, List<Integer> validateFileTypeList) {
        // 参数校验
        FileUtil.validateFile(file, validateFileTypeList);
        return fileUpload(fileUrl, fileName, file);
    }

    private SysAttachment commonFileUpload(String fileUrl, String fileName, MultipartFile file, Map<Integer, Long> fileTypeSizeMap) {
        // 参数校验
        FileUtil.validateFile(file, fileTypeSizeMap);
        return fileUpload(fileUrl, fileName, file);
    }

    private SysAttachment commonFileUpload(String fileUrl, String fileName, MultipartFile file) {
        return fileUpload(fileUrl, fileName, file);
    }

    private SysAttachment fileUpload(String fileUrl, String fileName, MultipartFile file) {
        SysAttachment erpAttachment;
        try {
            String originFileName = file.getOriginalFilename();
            assert originFileName != null;
            String newFileName = UUID.randomUUID() + originFileName.substring(originFileName.lastIndexOf("."));
            if (StringUtils.isNotBlank(fileName)) {
                originFileName = fileName + originFileName.substring(originFileName.lastIndexOf("."));
            }
            //String relDirectory = upload.replaceAll("file:", "") + fileUrl;
            String relDirectory="C:\\Users\\12116\\Desktop\\rouces"+fileUrl;
            File fi = new File(relDirectory);
            if (!fi.isDirectory()) {
                //先得到文件的上级目录，并创建上级目录，在创建文件
                fi.mkdirs();
            }
            File uploadFile = new File(relDirectory, newFileName);
            file.transferTo(uploadFile);
            erpAttachment = new SysAttachment();
            long currentTimeStamp = Instant.now().toEpochMilli();
            erpAttachment.setTime(currentTimeStamp);
            erpAttachment.setFileName(newFileName);
            erpAttachment.setFileOriginName(originFileName);
            erpAttachment.setFilePath(fileUrl.startsWith("/") ? fileUrl + newFileName : "/" + fileUrl + newFileName);
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            throw new BusinessException(e.getMessage());
        }
        return erpAttachment;
    }


    @Override
    public Boolean deleteSingleFile(String fileId) {
        SysAttachment erpAttachment = attachmentService.getById(fileId);
        if (ObjectUtil.isNotNull(erpAttachment)) {
            // 删除文件
            FileUtil.deleteFile(upload.replaceAll("file:", "") + erpAttachment.getFilePath());
        }
        System.out.println(fileId);
        return attachmentService.removeById(fileId);
    }

    @Override
    public Boolean deleteBatchFile(List<String> fileIds) {
        List<SysAttachment> erpAttachmentList = attachmentService.listByIds(fileIds);
        for (SysAttachment erpAttachment : erpAttachmentList) {
            // 删除文件
            FileUtil.deleteFile(upload.replaceAll("file:", "") + erpAttachment.getFilePath());
        }
        return attachmentService.removeByIds(fileIds);
    }

    private static final String VIEWS_KEY_PREFIX = "attachment:views:";

    @Resource
    private RedisTemplate<String, Long> redisTemplate;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean insertViews(String attachmentId) {
        Long views = redisTemplate.opsForValue().increment(VIEWS_KEY_PREFIX + attachmentId, 1);
        if (views == null) {
            SysAttachment attachment = sysAttachmentMapper.selectById(attachmentId);
            if (attachment!= null) {
                long currentViews = attachment.getViews();
                redisTemplate.opsForValue().set(VIEWS_KEY_PREFIX + attachmentId, currentViews + 1, 1, TimeUnit.DAYS);
            }
        }
        if (views!= null && views % 1000 == 0) {
            SysAttachment attachment = sysAttachmentMapper.selectById(attachmentId);
            if (attachment!= null) {
                attachment.setViews(redisTemplate.opsForValue().get(VIEWS_KEY_PREFIX + attachmentId));
                sysAttachmentMapper.updateById(attachment);
            }
        }
        return true;
    }
}

